package com.fitz.remote.handler;

import com.fitz.common.Constant;
import com.fitz.remote.model.RpcRequest;
import com.fitz.remote.model.RpcResponse;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.lang.reflect.Method;
import java.util.Map;

/**
 * @author fitz 2020-5-14 13:58
 */
public class RpcServerHandler extends SimpleChannelInboundHandler<RpcRequest> {

    private static final Logger logger = LoggerFactory.getLogger(RpcServerHandler.class);

    private final Map<String, Object> handlerMap;

    public RpcServerHandler(Map<String, Object> handlerMap) {
        this.handlerMap = handlerMap;
    }

    @Override
    protected void channelRead0(ChannelHandlerContext ctx, RpcRequest rpcRequest) throws Exception {
        logger.info("服务端收到消息:{}",rpcRequest.toString());
        RpcResponse rpcResponse = (RpcResponse) handle(rpcRequest);
        ctx.channel().writeAndFlush(rpcResponse);
    }

    private Object handle(RpcRequest rpcRequest){
        RpcResponse rpcResponse = new RpcResponse();
        rpcResponse.setRequestId(rpcRequest.getRequestId());
        String className = rpcRequest.getClassName();
        Object serviceBean = handlerMap.get(className);

        if ((System.currentTimeMillis() - rpcRequest.getCreateTime()) > (rpcRequest.getTimeout()==0? Constant.DEFAULT_TIMEOUT :rpcRequest.getTimeout())){
            rpcResponse.setErrorMessage("Service remote call timeout ");
            return rpcResponse;
        }

        Class<?> serviceClass = serviceBean.getClass();
        String methodName = rpcRequest.getMethodName();
        Class<?>[] paramsType = rpcRequest.getParamsType();
        Object[] params = rpcRequest.getParams();

        try {
            Method method = serviceClass.getMethod(methodName,paramsType);
            method.setAccessible(true);
            Object result =  method.invoke(serviceBean, params);
            rpcResponse.setResult(result);
        } catch (Throwable e) {
            e.printStackTrace();
            rpcResponse.setErrorMessage(e.getMessage());
        }
        return rpcResponse;
    }

    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        super.channelActive(ctx);
        logger.info("客户端连接成功~");
    }
}
